
import static java.lang.System.*;
import java.util.*;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import org.omg.SendingContext.RunTime;

/**
 * MyComponentContainer class is the parent for all new tools
 * The class handles selection border, object drag and resize
 */
public class MyComponentContainer implements Serializable {

    protected JComponent myComponent;
    protected MyFrame frame;
    private boolean chosen;
    protected JPanel dragAnchor;
    protected JPanel resizeAnchor[] = new JPanel[7];
    private String namePressed;
    private int xFirst,  yFirst,  x2First,  y2First;
    private int widthFirst,  heightFirst;
    protected int clickToAnchorX,  clickToAnchorY;
    protected boolean flagDrag;
    protected boolean flagUndo;

    MyComponentContainer(JComponent c, MyFrame frame) {
        myComponent = c;
        this.frame = frame;
        /**
         * Border setup
         * The border have one edge for draging and the other edges are for object resize,
         * it consists of panels that created at object creation rather that creating at first use
         */
        BorderHandler borderHandler = new BorderHandler();
        dragAnchor = new JPanel();
        dragAnchor.addMouseListener(borderHandler);
        dragAnchor.addMouseMotionListener(new DragHandler());
        ResizeHandler resizeHandler = new ResizeHandler();
        for (int i = 0; i < 7; i++) {
            resizeAnchor[i] = new JPanel();
            resizeAnchor[i].setSize(5, 5);
            resizeAnchor[i].setBackground(Color.BLACK);
            resizeAnchor[i].addMouseListener(borderHandler);
            resizeAnchor[i].addMouseMotionListener(resizeHandler);
        }
    }
    //#########################################################################

    public JComponent getComponent() {
        return myComponent;
    }

    public boolean isChosen() {
        return chosen;
    }
    //#########################################################################

    public void setChosen(boolean c) {
        chosen = c;
    }
    //#########################################################################

    protected class ResizeHandler extends MouseMotionAdapter {

        public void mouseDragged(MouseEvent evt) {
            if (evt.getModifiers() == 16) {
                int x, y;
                x = evt.getX();
                y = evt.getY();
                if (evt.getComponent().getName().equals(namePressed)) {
                    JPanel anchor = (JPanel) evt.getComponent();

                    if (anchor.getName().equals("N")) {
                        try {
                            int ySecond = (int) evt.getComponent().getParent().getMousePosition().getY();
                            if (ySecond <= y2First) {
                                myComponent.setLocation(myComponent.getX(), ySecond);
                                myComponent.setSize(myComponent.getWidth(), y2First - ySecond);
                            } else {
                                myComponent.setLocation(myComponent.getX(), y2First);
                                myComponent.setSize(myComponent.getWidth(), ySecond - y2First);
                            }
                        } catch (NullPointerException e) {
                            frame.panel.setSize(frame.panel.getWidth(), frame.panel.getHeight() + 15);
                        }
                    } else if (anchor.getName().equals("NE")) {
                        try {
                            int xSecond = (int) evt.getComponent().getParent().getMousePosition().getX();
                            int ySecond = (int) evt.getComponent().getParent().getMousePosition().getY();

                            if (xSecond >= xFirst) {
                                if (ySecond <= y2First) {
                                    myComponent.setLocation(xFirst, ySecond);
                                    myComponent.setSize(myComponent.getWidth() + x, y2First - ySecond);
                                } else {
                                    myComponent.setLocation(xFirst, y2First);
                                    myComponent.setSize(myComponent.getWidth() + x, ySecond - y2First);
                                }
                            } else {
                                if (ySecond <= y2First) {
                                    myComponent.setSize(xFirst - xSecond, y2First - ySecond);
                                    myComponent.setLocation(xSecond, ySecond);
                                } else {
                                    myComponent.setSize(xFirst - xSecond, ySecond - y2First);
                                    myComponent.setLocation(xSecond, y2First);
                                }
                            }
                        } catch (NullPointerException e) {
                            frame.panel.setSize(frame.panel.getWidth() + 15, frame.panel.getHeight() + 15);
                        }
                    } else if (anchor.getName().equals("S")) {
                        try {
                            int ySecond = (int) evt.getComponent().getParent().getMousePosition().getY();
                            if (ySecond >= yFirst) {
                                myComponent.setSize(myComponent.getWidth(), ySecond - yFirst);
                            } else {
                                myComponent.setLocation(xFirst, ySecond);
                                myComponent.setSize(myComponent.getWidth(), yFirst - ySecond);
                            }
                        } catch (NullPointerException e) {
                            frame.panel.setSize(frame.panel.getWidth(), frame.panel.getHeight() + 15);
                        }
                    } else if (anchor.getName().equals("SE")) {
                        try {
                            int xSecond = (int) evt.getComponent().getParent().getMousePosition().getX();
                            int ySecond = (int) evt.getComponent().getParent().getMousePosition().getY();

                            if (xSecond >= xFirst) {
                                if (ySecond >= yFirst) {
                                    myComponent.setSize(myComponent.getWidth() + x, ySecond - yFirst);
                                } else {
                                    myComponent.setLocation(xFirst, ySecond);
                                    myComponent.setSize(myComponent.getWidth() + x, yFirst - ySecond);
                                }
                            } else {
                                if (ySecond >= yFirst) {
                                    myComponent.setSize(xFirst - xSecond, ySecond - yFirst);
                                    myComponent.setLocation(xSecond, yFirst);
                                } else {
                                    myComponent.setSize(xFirst - xSecond, yFirst - ySecond);
                                    myComponent.setLocation(xSecond, ySecond);
                                }
                            }
                        } catch (NullPointerException e) {
                            frame.panel.setSize(frame.panel.getWidth() + 15, frame.panel.getHeight() + 15);
                        }
                    } else if (anchor.getName().equals("SW")) {
                        try {
                            int xSecond = (int) evt.getComponent().getParent().getMousePosition().getX();
                            int ySecond = (int) evt.getComponent().getParent().getMousePosition().getY();

                            if (xSecond <= x2First) {
                                if (ySecond >= yFirst) {
                                    myComponent.setSize((xFirst - xSecond) + widthFirst, ySecond - yFirst);
                                    myComponent.setLocation(xSecond, yFirst);
                                } else {
                                    myComponent.setSize((xFirst - xSecond) + widthFirst, yFirst - ySecond);
                                    myComponent.setLocation(xSecond, ySecond);
                                }
                            } else {
                                if (ySecond >= yFirst) {
                                    myComponent.setSize(xSecond - x2First, ySecond - yFirst);
                                    myComponent.setLocation(x2First, yFirst);
                                } else {
                                    myComponent.setSize(xSecond - x2First, yFirst - ySecond);
                                    myComponent.setLocation(x2First, ySecond);
                                }
                            }
                        } catch (NullPointerException e) {
                            frame.panel.setSize(frame.panel.getWidth() + 15, frame.panel.getHeight() + 15);
                        }
                    } else if (anchor.getName().equals("W")) {
                        try {
                            int xSecond = (int) evt.getComponent().getParent().getMousePosition().getX();
                            if (xSecond <= x2First) {
                                myComponent.setLocation(xSecond, myComponent.getY());
                                myComponent.setSize(xFirst - xSecond + widthFirst, myComponent.getHeight());
                            } else {
                                myComponent.setLocation(x2First, myComponent.getY());
                                myComponent.setSize(xSecond - x2First, myComponent.getHeight());
                            }
                        } catch (NullPointerException e) {
                            frame.panel.setSize(frame.panel.getWidth() + 15, frame.panel.getHeight());
                        }
                    } else if (anchor.getName().equals("E")) {
                        try {
                            int xSecond = (int) evt.getComponent().getParent().getMousePosition().getX();
                            if (xSecond >= xFirst) {
                                myComponent.setSize(myComponent.getWidth() + x, myComponent.getHeight());
                            } else {
                                myComponent.setLocation(xSecond, myComponent.getY());
                                myComponent.setSize(xFirst - xSecond, myComponent.getHeight());
                            }
                        } catch (NullPointerException e) {
                            frame.panel.setSize(frame.panel.getWidth() + 15, frame.panel.getHeight());
                        }

                    }
                    frame.flagDirty = true;
                    frame.toolbar.toolSave.setEnabled(true);
                    frame.saveItem.setEnabled(true);
                    flagUndo = true;
                    showBorder();
                }
            }
        }
    }
    //#########################################################################

    protected class BorderHandler extends MouseAdapter {

        public void mouseEntered(MouseEvent m) {
            JPanel anchor = (JPanel) m.getComponent();

            if (anchor.getName().equals("N")) {
                frame.panel.setCursor(new Cursor(Cursor.N_RESIZE_CURSOR));
            } else if (anchor.getName().equals("NE")) {
                frame.panel.setCursor(new Cursor(Cursor.NE_RESIZE_CURSOR));
            } else if (anchor.getName().equals("NW")) {
                frame.panel.setCursor(new Cursor(Cursor.HAND_CURSOR));
            } else if (anchor.getName().equals("S")) {
                frame.panel.setCursor(new Cursor(Cursor.S_RESIZE_CURSOR));
            } else if (anchor.getName().equals("SE")) {
                frame.panel.setCursor(new Cursor(Cursor.SE_RESIZE_CURSOR));
            } else if (anchor.getName().equals("SW")) {
                frame.panel.setCursor(new Cursor(Cursor.SW_RESIZE_CURSOR));
            } else if (anchor.getName().equals("W")) {
                frame.panel.setCursor(new Cursor(Cursor.W_RESIZE_CURSOR));
            } else if (anchor.getName().equals("E")) {
                frame.panel.setCursor(new Cursor(Cursor.E_RESIZE_CURSOR));
            }
        }

        public void mouseExited(MouseEvent m) {
            if (m.getModifiers() == 0) {
                frame.panel.setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
            } else if (!m.getComponent().getName().equals("NW")) {
                frame.panel.setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
            }
        }

        public void mousePressed(MouseEvent m) {
            namePressed = m.getComponent().getName();
            xFirst = myComponent.getX();
            yFirst = myComponent.getY();
            x2First = myComponent.getX() + myComponent.getWidth();
            y2First = myComponent.getY() + myComponent.getHeight();
            ;
            widthFirst = myComponent.getWidth();
            heightFirst = myComponent.getHeight();
        }

        public void mouseReleased(MouseEvent m) {
            handleUndo();
        }
    }
    //#########################################################################

    protected class DragHandler extends MouseMotionAdapter {

        public void mouseDragged(MouseEvent evt) {
            int x, y;
            x = evt.getX();
            y = evt.getY();
            int newX = myComponent.getX() + x;
            int newY = myComponent.getY() + y;
            if (newX > 0) {
                if (newY > 5) {
                    myComponent.setLocation(newX, newY);
                } else {
                    myComponent.setLocation(newX, 5);
                }
            } else {
                if (newY > 5) {
                    myComponent.setLocation(0, newY);
                } else {
                    myComponent.setLocation(0, 5);
                }
            }
            showBorder();
            resizePanel();
            frame.flagDirty = true;
            frame.toolbar.toolSave.setEnabled(true);
            frame.saveItem.setEnabled(true);
            flagUndo = true;
        }
    }
    //#########################################################################

    protected void hideBorder() {
        frame.panel.remove(dragAnchor);
        for (int i = 0; i < 7; i++) {
            frame.panel.remove(resizeAnchor[i]);
        }
        frame.panel.repaint();
        frame.panel.validate();
    }
    //#########################################################################

    protected void showBorder() {
        dragAnchor.setLocation(myComponent.getX() - 9, myComponent.getY() - 9);
        dragAnchor.setSize(10, 10);
        dragAnchor.setBackground(Color.BLACK);
        dragAnchor.setName("NW");

        resizeAnchor[0].setLocation(myComponent.getX() + (myComponent.getWidth() / 2) - 2, myComponent.getY() - 4);
        resizeAnchor[0].setName("N");
        resizeAnchor[1].setLocation(myComponent.getX() + myComponent.getWidth() - 1, myComponent.getY() - 4);
        resizeAnchor[1].setName("NE");
        resizeAnchor[2].setLocation(myComponent.getX() - 4, myComponent.getY() + myComponent.getHeight() - 1);
        resizeAnchor[2].setName("SW");
        resizeAnchor[3].setLocation(myComponent.getX() + (myComponent.getWidth() / 2) - 2, myComponent.getY() + myComponent.getHeight());
        resizeAnchor[3].setName("S");
        resizeAnchor[4].setLocation(myComponent.getX() - 4, myComponent.getY() + (myComponent.getHeight() / 2) - 2);
        resizeAnchor[4].setName("W");
        resizeAnchor[5].setLocation(myComponent.getX() + myComponent.getWidth() - 1, myComponent.getY() + (myComponent.getHeight() / 2) - 2);
        resizeAnchor[5].setName("E");
        resizeAnchor[6].setLocation(myComponent.getX() + myComponent.getWidth() - 1, myComponent.getY() + myComponent.getHeight() - 1);
        resizeAnchor[6].setName("SE");
        frame.panel.add(dragAnchor, 0);

        for (int i = 0; i < 7; i++) {
            frame.panel.add(resizeAnchor[i], 0);
        }
        frame.panel.repaint();
    }
    //#########################################################################

    protected void handleDrag(MouseEvent evt) {
        if (evt.getModifiers() == 16) {
            if (isChosen() == false) {
                setChosen(true);
                showBorder();
            }
            if (evt.getComponent().isVisible()) {
                flagDrag = false;
                for (MyComponentContainer c : frame.componentList) {
                    if (c.isChosen()) {
                        int x, y;
                        x = (int) c.getComponent().getX();
                        y = (int) c.getComponent().getY();
                        int newX = x + (evt.getX() - clickToAnchorX);
                        int newY = y + (evt.getY() - clickToAnchorY);
                        if (newX <= 5 || newY <= 5) {
                            flagDrag = true;
                            frame.flagDirty = true;
                            frame.toolbar.toolSave.setEnabled(true);
                            frame.saveItem.setEnabled(true);
                            flagUndo = true;
                        }
                    }
                }

                if (flagDrag == false) {
                    for (MyComponentContainer c : frame.componentList) {
                        if (c.isChosen()) {
                            int x, y;
                            x = (int) c.getComponent().getX();
                            y = (int) c.getComponent().getY();
                            int newX = x + (evt.getX() - clickToAnchorX);
                            int newY = y + (evt.getY() - clickToAnchorY);
                            if (newX > 5) {
                                if (newY > 5) {
                                    c.getComponent().setLocation(newX, newY);
                                } else {
                                    c.getComponent().setLocation(newX, 5);
                                }
                            } else {
                                if (newY > 5) {
                                    c.getComponent().setLocation(5, newY);
                                } else {
                                    c.getComponent().setLocation(5, 5);
                                }
                            }
                            c.showBorder();
                            resizePanel();
                            frame.flagDirty = true;
                            frame.toolbar.toolSave.setEnabled(true);
                            frame.saveItem.setEnabled(true);
                            flagUndo = true;
                        }
                    }
                }
            }
        }
    }
    //#########################################################################

    protected void handleSelection(MouseEvent m) {
        if (m.isShiftDown() == false) {
            boolean flagSelection = false;
            frame.selectedComponentList.add(myComponent.getName());
            int i = frame.selectedComponentList.size() - 1;
            if (i >= 1) {
                for (int z = 0; z < i; z++) {
                    String c = (String) frame.selectedComponentList.elementAt(z);
                    if (c.equals(myComponent.getName())) {
                        flagSelection = true;
                    }
                }
            }

            if (flagSelection == false) {
                if (frame.selectedComponentList.size() != 1) {
                    frame.selectedComponentList.removeAllElements();
                }
                frame.formatToolBar.setSelectedComponent(myComponent.getName());
                frame.formatToolBar.enableButtons(this);
                for (MyComponentContainer c : frame.componentList) {
                    if (c.isChosen() && !c.getComponent().getName().equals(myComponent.getName())) {
                        c.hideBorder();
                        c.setChosen(false);
                    }
                }
            }
        } else {
            if (this.isChosen()) {
                this.setChosen(false);
                this.hideBorder();
                frame.selectedComponentList.remove(myComponent.getName());
            } else {
                this.showBorder();
                this.setChosen(true);
                frame.formatToolBar.setSelectedComponent(null);
                frame.formatToolBar.enableButtons(null);
                frame.selectedComponentList.add(myComponent.getName());
            }
        }
        frame.duplicateItem.setEnabled(true);
        frame.deleteItem.setEnabled(true);
        frame.copyItem.setEnabled(true);
        frame.cutItem.setEnabled(true);
        frame.toolbar.toolCopy.setEnabled(true);
        frame.toolbar.toolCut.setEnabled(true);
    }
    //#########################################################################

    protected void resizePanel() {
        int maxX = frame.getMaxX();
        int maxY = frame.getMaxY();
        int panelHeight = frame.panel.getHeight() + frame.panel.getY();
        int panelWidth = frame.panel.getWidth() + frame.panel.getX();

        if (maxX > panelWidth && maxY > panelHeight) {
            frame.panel.setSize(maxX + 10, maxY + 10);
        } else {
            if (maxX > panelWidth) {
                frame.panel.setSize(maxX + 10, panelHeight);
            }
            if (maxY > panelHeight) {
                frame.panel.setSize(panelWidth, maxY + 10);
            }
        }
        frame.autoscrollPanel();
    }
    //#########################################################################

    public void setFrame(MyFrame frame) {
        this.frame = frame;
    }
    //#########################################################################

    public String getName() {
        return (this.getComponent().getName());
    }

    public String getNamePressed() {
        return namePressed;
    }

    public void handleRightClickSelection() {
        boolean flagSelection = false;
        frame.selectedComponentList.add(myComponent.getName());
        int i = frame.selectedComponentList.size() - 1;
        if (i >= 1) {
            for (int z = 0; z < i; z++) {
                String c = (String) frame.selectedComponentList.elementAt(z);
                if (c.equals(myComponent.getName())) {
                    flagSelection = true;
                }
            }
        }

        if (flagSelection == false) {
            if (frame.selectedComponentList.size() != 1) {
                frame.selectedComponentList.removeAllElements();
            }
            frame.formatToolBar.setSelectedComponent(myComponent.getName());
            frame.formatToolBar.enableButtons(this);
            for (MyComponentContainer c : frame.componentList) {
                if (c.isChosen() && !c.getComponent().getName().equals(myComponent.getName())) {
                    c.hideBorder();
                    c.setChosen(false);
                }
            }
        }
        frame.duplicateItem.setEnabled(true);
        frame.deleteItem.setEnabled(true);
        frame.copyItem.setEnabled(true);
        frame.cutItem.setEnabled(true);
        frame.toolbar.toolCopy.setEnabled(true);
        frame.toolbar.toolCut.setEnabled(true);
    }

    public void handleUndo() {
        if (flagUndo) {
            frame.toolbar.toolUndo.setEnabled(true);
            frame.undoItem.setEnabled(true);
            ArrayList<MyComponentContainer> myComponentList = new ArrayList<MyComponentContainer>();
            for (MyComponentContainer c : frame.componentList) {
                myComponentList.add(ComponentClone.clone(c));
            }
            UndoHistoryInformation undoHistoryInfo = new UndoHistoryInformation(myComponentList, frame.panel.getSize(), frame.panel.getBackground());
            if (frame.toolbar.toolRedo.isEnabled()) {
                if (frame.undoHistory.size() >= MainWindow.undoHistoryLimit) {
                    frame.undoHistory.remove(0);
                    frame.undoHistory.remove(0);
                    frame.undoHistory.add(frame.undoHistory.get(frame.undoIndex - 2));
                    frame.undoHistory.add(undoHistoryInfo);
                } else {
                    frame.undoHistory.add(frame.undoHistory.get(frame.undoIndex));
                    frame.undoHistory.add(undoHistoryInfo);
                }
                frame.undoIndex = frame.undoHistory.size() - 1;
                frame.toolbar.toolRedo.setEnabled(false);
                frame.redoItem.setEnabled(false);
            } else {
                if (frame.undoHistory.size() >= MainWindow.undoHistoryLimit) {
                    frame.undoHistory.remove(0);
                    frame.undoIndex = MainWindow.undoHistoryLimit - 1;
                } else {
                    frame.undoIndex++;
                }
                frame.undoHistory.add(undoHistoryInfo);
            }
            flagUndo = false;
        }
    }

    public void setName(String name) {
        this.getComponent().setName(name);
    }
}
